#include "Arena.h"

Arena :: Arena(int _xMax, int _yMax) : xMax(_xMax), yMax(_yMax) {
	screen = new char*[_yMax];
	firedPoints = new bool*[_yMax];
	nearestBoat = new bool*[_yMax];
	for (int i = 0; i < _yMax; ++i) {
		screen[i] = new char[_xMax];
		firedPoints[i] = new bool[_xMax];
		nearestBoat[i] = new bool[_xMax];
	}
	reset();
}

Arena :: Arena(const Arena& snd) {
	xMax = snd.xMax;
	yMax = snd.yMax;
	screen = new char*[yMax];
	firedPoints = new bool*[yMax];
	nearestBoat = new bool*[yMax];
	for (int i = 0; i < yMax; ++i) {
		screen[i] = new char[xMax];
		firedPoints[i] = new bool[xMax];
		nearestBoat[i] = new bool[xMax];
		for (int j = 0; j < xMax; ++j) {
			screen[i][j] = snd.screen[i][j];
			firedPoints[i][j] = snd.firedPoints[i][j];
			nearestBoat[i][j] = snd.nearestBoat[i][j];
		}
	}
}

Arena :: ~Arena() {
	for (unsigned int i = 0; i < yMax; ++i) {
		delete[] screen[i];
		delete[] firedPoints[i];
		delete[] nearestBoat[i];
	}
	delete[] screen;
	delete[] firedPoints;
	delete[] nearestBoat;
}

void Arena :: setPoint(const Point<int>& x) throw(OutOfBound, OverlapBoat, TooNearBoat) {
	if (x.getX() < xMax && x.getY() < yMax) {
		if (screen[x.getY()][x.getX()] == blankCh) {
			if (!nearestBoat[x.getY()][x.getX()]) {
				screen[x.getY()][x.getX()] = boatCh;
			}
			else {
				throw TooNearBoat();
			}
		}
		else throw OverlapBoat();
	}
	else {
		throw OutOfBound();
	}
}

void Arena :: setWaterPoint(const Point<int>& x) {
	screen[x.getY()][x.getX()] = waterCh;
}

void Arena :: setFiredPoint(const Point<int>& x) {
	screen[x.getY()][x.getX()] = firedCh;
}

void Arena :: setDestroyedPoint(const Point<int>& x) {
	screen[x.getY()][x.getX()] = destroyedCh;
}

void Arena :: fireToPoint(const Point<int>& pt) throw(DoubleFiredPoint, OutOfBound) {
	if (pt.getX() >= xMax || pt.getX() < 0 || pt.getY() >= yMax || pt.getY() < 0) {
		throw OutOfBound();
	}
	if (firedPoints[pt.getY()][pt.getX()]) {
		throw DoubleFiredPoint();
	}
	else {
		firedPoints[pt.getY()][pt.getX()] = true;
	}
}

void Arena::updateNearestConfiguration() {
	for (unsigned int i = 0; i < yMax; ++i) {
		for (unsigned int j = 0; j < xMax; ++i) {
			if (screen[i][j] != blankCh && screen[i][j] != waterCh) nearestBoat[i][j] = true;
		}
	}
	for (unsigned int i = 0; i < yMax - 1; ++i) {
		for (unsigned int j = 0; j < xMax; ++i) {
			if (screen[i][j] != blankCh && screen[i][j] != waterCh) nearestBoat[i+1][j] = true;
		}
	}
	for (unsigned int i = 0; i < yMax; ++i) {
		for (unsigned int j = 0; j < xMax - 1; ++i) {
			if (screen[i][j] != blankCh && screen[i][j] != waterCh) nearestBoat[i][j+1] = true;
		}
	}
	for (unsigned int i = 0; i < yMax - 1; ++i) {
		for (unsigned int j = 0; j < xMax - 1; ++i) {
			if (screen[i][j] != blankCh && screen[i][j] != waterCh) nearestBoat[i+1][j+1] = true;
		}
	}
	for (unsigned int i = 1; i < yMax; ++i) {
		for (unsigned int j = 0; j < xMax; ++i) {
			if (screen[i][j] != blankCh && screen[i][j] != waterCh) nearestBoat[i-1][j] = true;
		}
	}
	for (unsigned int i = 0; i < yMax; ++i) {
		for (unsigned int j = 1; j < xMax; ++i) {
			if (screen[i][j] != blankCh && screen[i][j] != waterCh) nearestBoat[i][j-1] = true;
		}
	}
	for (unsigned int i = 1; i < yMax; ++i) {
		for (unsigned int j = 1; j < xMax; ++i) {
			if (screen[i][j] != blankCh && screen[i][j] != waterCh) nearestBoat[i-1][j-1] = true;
		}
	}
	for (unsigned int i = 1; i < yMax; ++i) {
		for (unsigned int j = 0; j < xMax-1; ++i) {
			if (screen[i][j] != blankCh && screen[i][j] != waterCh) nearestBoat[i-1][j+1] = true;
		}
	}
	for (unsigned int i = 0; i < yMax-1; ++i) {
		for (unsigned int j = 1; j < xMax; ++i) {
			if (screen[i][j] != blankCh && screen[i][j] != waterCh) nearestBoat[i+1][j-1] = true;
		}
	}
}

void Arena::reset() {
	for (unsigned int i = 0; i < yMax; ++i) {
		for (unsigned int j = 0; j < xMax; ++j) {
			screen[i][j] = blankCh;
			firedPoints[i][j] = false;
			nearestBoat[i][j] = false;
		}
	}
}

Color Arena::getNormalColor(const Point<int>& pt) {
	switch (screen[pt.getY()][pt.getX()]) {
		case blankCh:
			return HIDDEN;
		case waterCh:
			return WATER;
		case boatCh:
			return BOAT;
		case firedCh:
			return FIRED;
		case destroyedCh:
			return DESTROYED;
	}
}

Color Arena::getHideColor(const Point<int>& pt) {
	switch (screen[pt.getY()][pt.getX()]) {
		case blankCh:
			return HIDDEN;
		case waterCh:
			return WATER;
		case boatCh:
			return HIDDEN;
		case firedCh:
			return FIRED;
		case destroyedCh:
			return DESTROYED;
	}
}

bool Arena :: isDestroyed(const Point<int>& pt) {
	if (pt.getX() >= 0 && pt.getY() >= 0 && pt.getX() < xMax && pt.getY() < yMax) return screen[pt.getY()][pt.getX()] == destroyedCh;
	else return false;
}

bool Arena :: isFired(const Point<int>& pt) {
	if (pt.getX() >= 0 && pt.getY() >= 0 && pt.getX() < xMax && pt.getY() < yMax) return screen[pt.getY()][pt.getX()] == firedCh;
	else return false;
}

bool Arena :: isShadow(const Point<int>& pt) {
	if (pt.getX() >= 0 && pt.getY() >= 0 && pt.getX() < xMax && pt.getY() < yMax) return screen[pt.getY()][pt.getX()] == blankCh || screen[pt.getY()][pt.getX()] == boatCh;
	else return false;
}

bool Arena :: isWater(const Point<int>& pt) {
	if (pt.getX() >= 0 && pt.getY() >= 0 && pt.getX() < xMax && pt.getY() < yMax) return screen[pt.getY()][pt.getX()] == waterCh;
	else return false;
}

void Arena :: print() {
	for (int i = 0; i < yMax; ++i) {
		for (int j = 0; j < xMax; ++j) {
			cout << screen[i][j];
		}
		cout << endl;
	}
}
char Arena :: get(int i, int j) {
	return screen[i][j];
}

unsigned int Arena::getXMax() {
	return xMax;
}
unsigned int Arena::getYMax() {
	return yMax;
}

